package sindconsole.auth.service;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import lombok.Data;
import sindconsole.auth.bean.Permission;
import sindconsole.auth.bean.Role;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Data
public class AuthPredefinitions {

    @Data
    public static class RoleInfo extends Role {
        List<String> permissions;
    }

    private Map<String, Permission> permissions = new LinkedHashMap<>();
    private Map<String, RoleInfo> roles = new LinkedHashMap<>();

    public static AuthPredefinitions load() {
        SimpleModule module = new SimpleModule();
        module.addDeserializer(Permission.class, new StdDeserializer<Permission>(Permission.class) {
            @Override
            public Permission deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
                JsonNode node = jsonParser.getCodec().readTree(jsonParser);
                String label = node.isTextual() ? node.asText() : node.get("label").asText();
                Permission permission = new Permission();
                permission.setKey(jsonParser.currentName());
                permission.setLabel(label);
                return permission;
            }
        });
        module.addDeserializer(RoleInfo.class, new StdDeserializer<RoleInfo>(RoleInfo.class) {
            @Override
            public RoleInfo deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
                JsonNode node = jsonParser.getCodec().readTree(jsonParser);
                String label = node.get("label").asText();
                List<String> permissions = new ArrayList<>();
                for(JsonNode permission : node.get("permissions")) {
                    permissions.add(permission.asText());
                }
                RoleInfo role = new RoleInfo();
                role.setKey(jsonParser.currentName());
                role.setLabel(label);
                role.setPredefined(true);
                role.setPermissions(permissions);
                return role;
            }
        });
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
        objectMapper.registerModule(module);
        try {
            return objectMapper.readValue(AuthPredefinitions.class.getResourceAsStream("/auth-predefinitions.yml"), AuthPredefinitions.class);
        } catch (IOException e) {
            return new AuthPredefinitions();
        }
    }

    public Permission findPermission(String key) {
        return permissions.get(key);
    }

    public List<Permission> findPermissions() {
        return permissions.values().stream().collect(Collectors.toList());
    }

    public Role findRole(String key) {
        return roles.get(key);
    }

    public List<Role> findRoles() {
        return roles.values().stream().collect(Collectors.toList());
    }

}
